//
//  RouterManager.swift
//  Common
//
//  Created by yuyang on 2021/11/23.
//

import Foundation
import UIKit

public let Router = RouterManager.shared

public class RouterManager: NSObject {
    public static let shared = RouterManager()

    private var _router = [String: RouterNode]()
    
    private(set) var topNavigationController: UINavigationController?

    override init() {

    }

    /// 注册所有实现RouterRegisterProtocol协议的视图, 通过registerName使用前必须先注册
    public func setupMapBinding() {
//        let beginT = Date().timeIntervalSince1970

        let classNumber = objc_getClassList(nil, 0)
        var classBuffer = [AnyClass?](repeating: nil, count: Int(classNumber))

        classBuffer.withUnsafeMutableBufferPointer { buffer in
            let autoreleasingPointer = AutoreleasingUnsafeMutablePointer<AnyClass>(buffer.baseAddress)
            objc_getClassList(autoreleasingPointer, classNumber)
        }

        for aClass in classBuffer {
            if class_conformsToProtocol(aClass, RouterRegisterProtocol.self) {
                _registerPage(aClass!)
            }
        }

//        let endT = Date().timeIntervalSince1970
//        print(endT - beginT) // Memory 增加了6.0MB左右 第一次编译0.4365s 再次编译0.06s-0.20s
    }

    /// 注册window根视图 UINavigationController + rootViewController
    /// - Parameters:
    ///   - registerName: 页面注册名称
    ///   - params: 传值参数
    ///   - options: 配置选项
    /// - Returns: UINavigationController
    public func registerWindowRootViewController(_ registerName: String) -> UINavigationController {

        guard let vc = _createNewPage(registerName) else {
            assert(false, "aim vc do not register or do not found")
            return UINavigationController()
        }
        
        return registerWindowRootViewController(vc)
    }

    /// 注册window根视图 UINavigationController + rootViewController
    /// - Parameters:
    ///   - rootVC: 根视图VC
    ///   - params: 传值参数
    ///   - options: 配置选项
    /// - Returns: UINavigationController
    public func registerWindowRootViewController(_ rootVC: UIViewController) -> UINavigationController {

        let navi = UINavigationController(rootViewController: rootVC)
        topNavigationController = navi

        return navi
    }

    /// push页面
    /// - Parameters:
    ///   - registerName: 页面注册名称
    ///   - params: 传值参数
    ///   - options: 配置选项
    ///         - animated: Bool 是否需要push动画效果 默认true
    @discardableResult public func pushPage(_ registerName: String, params: [String: Any]? = nil, options: [String: Any]? = nil) -> UIViewController? {

        guard let pageNode = _getPageNode(registerName), let vc = pageNode.pageHandler?(registerName, params, options) else {
            return nil
        }

        return pushPage(vc, params: params, options: options)
    }

    /// push页面
    /// - Parameters:
    ///   - vc: ViewController
    ///   - params: 传值参数
    ///   - options: 配置选项
    ///         - animated: Bool 是否需要push动画效果 默认true
    @discardableResult public func pushPage(_ vc: UIViewController, params: [String: Any]? = nil, options: [String: Any]? = nil) -> UIViewController? {
        guard let nav = Router.topNavigationController else {
            return nil
        }

        var animated = true
        if let optAnimated = options?["animated"] as? Bool {
            animated = optAnimated
        }

        if vc.conforms(to: RouterRegisterProtocol.self) {
            (vc as! RouterRegisterProtocol).pageWillPushAppearReceive?(params: params, options: options)
        }

        nav.pushViewController(vc, animated: animated)
        return vc
    }

    /// pop页面
    /// - Parameter options: 配置选项
    ///         - animated: Bool 是否需要pop动画效果 默认true
    public func popPage(options: [String: Any]? = nil) {

        guard let nav = Router.topNavigationController else { return }

        var animated = true
        if let optAnimated = options?["animated"] as? Bool {
            animated = optAnimated
        }

        nav.popViewController(animated: animated)
    }

    /// pop到指定页面
    /// - Parameters:
    ///   - registerName: 页面注册名称
    ///   - params: 传值参数
    ///   - options: 配置选项
    ///         - animated: Bool 是否需要pop动画效果 默认true
    @discardableResult public func popToPage(_ registerName: String, params: [String: Any]? = nil, options: [String: Any]? = nil) -> UIViewController? {

        guard let vc = getStackPage(registerName) else { return nil }

        return popToPage(vc, params: params, options: options)
    }

    /// pop到指定页面
    /// - Parameters:
    ///   - vc: ViewController 需要传入堆栈中存在的vc实例
    ///   - params: 传值参数
    ///   - options: 配置选项
    ///         - animated: Bool 是否需要pop动画效果 默认true
    @discardableResult public func popToPage(_ vc: UIViewController, params: [String: Any]? = nil, options: [String: Any]? = nil) -> UIViewController? {

        guard let nav = Router.topNavigationController else { return nil }

        var animated = true
        if let optAnimated = options?["animated"] as? Bool {
            animated = optAnimated
        }

        if vc.conforms(to: RouterRegisterProtocol.self) {
            (vc as! RouterRegisterProtocol).pageWillPopToAppearReceive?(params: params, options: options)
        }

        nav.popToViewController(vc, animated: animated)
        return vc
    }

    /// pop到根页面
    /// - Parameter options: 配置选项
    ///         - animated: Bool 是否需要pop动画效果 默认true
    public func popToRootPage(options: [String: Any]? = nil) {
        guard let nav = Router.topNavigationController else { return }

        var animated = true
        if let optAnimated = options?["animated"] as? Bool {
            animated = optAnimated
        }

        nav.popToRootViewController(animated: animated)
    }

    /// 替换当前页面
    /// - Parameters:
    ///   - registerName: 目标页面注册名称
    ///   - params: 传值参数
    ///   - options: 配置选项
    ///         - animated: Bool 是否需要push动画效果 默认false
    @discardableResult public func replacePage(_ registerName: String, params: [String: Any]? = nil, options: [String: Any]? = nil) -> UIViewController? {

        guard let pageNode = _getPageNode(registerName), let vc = pageNode.pageHandler?(registerName, params, options) else {
            return nil
        }

        return replacePage(vc, params: params, options: options)
    }

    /// 替换当前页面
    /// - Parameters:
    ///   - vc: ViewController
    ///   - params: 传值参数
    ///   - options: 配置选项
    ///         - animated: Bool 是否需要push动画效果 默认false
    @discardableResult public func replacePage(_ vc: UIViewController, params: [String: Any]? = nil, options: [String: Any]? = nil) -> UIViewController? {

        guard let nav = Router.topNavigationController else {
            return nil
        }

        var animated = false
        if let optAnimated = options?["animated"] as? Bool {
            animated = optAnimated
        }

        if vc.conforms(to: RouterRegisterProtocol.self) {
            (vc as! RouterRegisterProtocol).pageWillPushAppearReceive?(params: params, options: options)
        }

        nav.popViewController(animated: false)
        nav.pushViewController(vc, animated: animated)

        return vc
    }

    /// 获取当前堆栈里存在的指定页面
    /// - Parameter name: 页面注册名称
    /// - Returns: 存在返回vc, 不存在返回nil
    public func getStackPage(_ registerName: String) -> (UIViewController & RouterRegisterProtocol)? {

        guard let vcs = topNavigationController?.viewControllers else {
            return nil
        }

        for vc in vcs.reversed() where vc is RouterRegisterProtocol {
            let tempVC = (vc as! RouterRegisterProtocol)
            if type(of: tempVC).registerName() == registerName {
                return vc as? (UIViewController & RouterRegisterProtocol)
            }
        }
        return nil
    }

    /// 获取当前页面
    /// - Returns: 存在返回vc, 不存在返回nil
    public func getCurrentPage() -> UIViewController? {
        return topNavigationController?.topViewController
    }

}

// MARK: - private func
private extension RouterManager {
    /// 注册页面
    func _registerPage(_ aClass: AnyClass) {
        guard (aClass as? UIViewController.Type) != nil && aClass.conforms(to: RouterRegisterProtocol.self) else {
            return
        }

        let pageRegister = aClass as! RouterRegisterProtocol.Type

        Router._registerPageNode(RouterNode(name: pageRegister.registerName(), pageType: .nativePage, pageHandler: { _, _, _ in
            let vc = (aClass as! UIViewController.Type).init() as! (UIViewController & RouterRegisterProtocol)
            return vc
        }))
    }

    /// 注册PageNode
    func _registerPageNode(_ pageNode: RouterNode) {
        _router[pageNode.name] = pageNode
    }

    /// 根据name创建一个新的页面
    func _createNewPage(_ registerName: String, params: [String: Any]? = nil, options: [String: Any]? = nil) -> (UIViewController & RouterRegisterProtocol)? {
        if let pageNode = _getPageNode(registerName), let vc = pageNode.pageHandler?(registerName, params, options) {
            return vc
        }

        return nil
    }

    /// 根据name获取映射的RouterNode对象
    func _getPageNode(_ registerName: String) -> RouterNode? {
        return _router[registerName]
    }
}
